// 前端排课算法

let langStr = {
  'cn': {
    weekMode:{
      odd: '单周',
      even: '双周',
    },
    // 0和7都是星期日 兼容一下
    week:['星期日','星期一','星期二','星期三','星期四','星期五','星期六','星期日']
  },
  'en': {
    weekMode:{
      odd: 'Odd',
      even: 'Even',
    },
    week:['Sun.','Mon.','Tue.','Wed.','Thur.','Fri.','Sat.','Sun.']
  },
}

let getCookie = (name)=>{
  var cookies = document.cookie;
  var list = cookies.split("; ");          // 解析出名/值对列表
      
  for(var i = 0; i < list.length; i++) {
    var arr = list[i].split("=");          // 解析出名和值
    if(arr[0] == name)
      return decodeURIComponent(arr[1]);   // 对cookie值解码
  } 
  return "";
}

let modeToString = (start,mode)=> {
  if (mode == 0) return ""
  let lang = getCookie('language')||'cn';
  return mode == 1?"": (start%2==0? langStr[lang].weekMode.even:langStr[lang].weekMode.odd);
}

let calcWeekState = (weeks)=>{
  let weekState = 0;
  let weekState2 = 0; //用于值大于 1<<31的运算
  for (let i = 0; i < weeks.length; i++) {
    let weekNum = weeks[i];
    if (weekNum <1 || weekNum >53){
      throw "周数必须在1-53之间"
    }
    if (weekNum<32){
      weekState |= 1 << weekNum - 1;
    } else {
      weekState2 |= 1 << weekNum - 32; // -31 -1
    }
  }
  return weekState2*2147483648 + weekState;
}
let splitWeekState = (weekState)=>{
  let weeks = [];
  let weekNum = 1;
  let weekState2 = 0;
  //9007199254740992 2的53次即二进制值第54为为1超过了一年最大周数 且js算术运算最大精确值为9007199254740992
  if (weekState<0 || weekState>=9007199254740992){
    throw "无效的weekstate"
  }
  // js的位运算只支持32为而第一位补码的位运算使用很不方便 当其值大于2^31次做特殊处理
  if (weekState > 2147483647){
    let mod = weekState % 2147483648
    weekState2 = (weekState - mod)/2147483648
    weekState = mod;
  }
  while (weekState > 0){
    if (weekState & 1){
      weeks.push(weekNum);
    }
    weekNum ++;
    weekState >>=1;
  }
  weekNum = 32;
  while (weekState2 > 0){
    if (weekState2 & 1){
      weeks.push(weekNum);
    }
    weekNum ++;
    weekState2 >>=1;
  }
  return weeks;
}

/**
 * 获取周字符串
 * @param {Number | Array<Number>} weeks weekstate值或者week数组
 */
let weekStateToString = (weeks)=>{
  if (weeks instanceof Array){
    weeks.sort((a,b)=>a-b);
  }else{
    weeks = splitWeekState(weeks);
  }
  let str = ""
  let arr = [];
  let mode;
  const toString = (arr,mode)=> `[${arr[0]}-${arr[arr.length-1]}${modeToString(arr[0],mode)}]`
  const reset = (weekNum)=>{
    if (arr.length == 0)
      return;
    str += toString(arr,mode);
    arr.length = 0;
    mode = 0;
    if (weekNum){
      arr.push(weekNum)
    }
  }
  
  for (let i = 0; i < weeks.length; i++) {
    const weekNum = weeks[i];
    if (arr.length == 0){
      arr.push(weekNum)
      mode = 0;
    }else if (arr.length == 1){
      let pre = arr[0];
      let cap = weekNum - pre;
      if (cap == 1){
        mode = 1;
        arr.push(weekNum);
      } else if (cap == 2){
        mode = 2;
        arr.push(weekNum)
      } else {
        reset(weekNum);
      }
    }else{
      let pre = arr[arr.length - 1];
      let cap = weekNum - pre;
      if (cap == 1){
        if (mode == 1)
          arr.push(weekNum);
        else
          reset(weekNum);
      } else if (cap == 2){
        if (mode == 2)
          arr.push(weekNum);
        else
          reset(weekNum);
      } else {
        reset(weekNum);
      }
    }
  }
  reset();
  return str;
}

/**
 * 获取timestate(位运算值)
 * @param {Number} day 
 * @param {Number} start 
 * @param {Number} end 
 */
let calcTimeState = (day,start,end)=> day-1+((1<< start-1 | 1<<end-1)<<3)

/**
 * calcTimeState的逆运算
 * @param {Number} timeState  calcTimeState函数的计算结果
 * @return {Object} {day,start,end}
 */
let splitTimeState = (timeState)=>{
  let startAndEnd = timeState >> 3;
  // 快速找到比上面值大的最小2的整数幂
  let cap = 1;
  let end = 0;
  while(cap<=startAndEnd){
    cap<<=1;
    end++;
  }
  let endBit = cap>>1;
  let startBit = startAndEnd - endBit;
  let start = 0;
  if (startBit == 0){
    start = end;
  }else {
    while(startBit > 0){
      startBit >>= 1;
      start++;
    }
  }
  return {
    day: (timeState & 7) + 1,
    start,
    end
  }
}

let checkConflict = (timetable1,timetable2)=>{
  let time1 = 1<< timetable1.timeStart-1 | 1<<timetable1.timeEnd-1;
  let time2 = 1<< timetable2.timeStart-1 | 1<<timetable2.timeEnd-1;
  return (timetable1.weekState&timetable2.weekState)>0 && (time1&time2)>0 && timetable1.dayOfWeek==timetable2.dayOfWeek 
}

let checkTime  = (timetable1,timetable2)=>{
  let time1 = 1<< timetable1.timeStart-1 | 1<<timetable1.timeEnd-1;
  let time2 = 1<< timetable2.timeStart-1 | 1<<timetable2.timeEnd-1;
  return (time1&time2)>0 && timetable1.dayOfWeek==timetable2.dayOfWeek 
}

let checkWeekState = (timetable1,timetable2)=>(timetable1.weekState&timetable2.weekState)>0

let dayTimeToString = (day,start,end)=>{
  let lang = getCookie('language')||'cn';
  let weekStr = langStr[lang].week;
  return `${weekStr[day%7]} ${start}-${end}${lang=='cn'?'节':''}`
}

let dayTimeTeachterToString = (day,timeStart,timeEnd,profile)=>{
  let lang = getCookie('language')||'cn';
  let weekStr = langStr[lang].week;
  return `${weekStr[day%7]} ${timeStart}-${timeEnd}${lang=='cn'?'节':''}${profile}`
}


export {
  calcWeekState,
  splitWeekState,
  weekStateToString,
  calcTimeState,
  splitTimeState,
  checkConflict,
  checkTime,
  checkWeekState,
  dayTimeToString,
  dayTimeTeachterToString
}
